﻿using System;

namespace SkeinLibManaged
{   /// <summary>
    /// Managed C# library for the Skein crypto hash algorithm.
    /// </summary>
    public partial class Skein
    {   //===HEADER===

        //CONSTANTS
        private const UInt32 SKEIN_VERSION	   = 0x00000001;     // base major version ONE (1)
        private const UInt32 SKEIN_SCHEMA_ID   = 0x33414853;     // (0x33414853) = "SHA3" in ASCII per the white paper
        private const UInt64 SKEIN_VS = (UInt64)(((UInt64)SKEIN_VERSION << 32) + SKEIN_SCHEMA_ID);

        private const UInt64 SKEIN_FLAG_FIRST  = 0x4000000000000000;
        private const UInt64 SKEIN_FLAG_FINAL  = 0x8000000000000000;

        private const UInt64 SKEIN_TYPE_KEY    = 0x0000000000000000;   // Skein being used for MAC, this is the Key block. (optional but done FIRST)
        private const UInt64 SKEIN_TYPE_CONFIG = 0x0400000000000000;   // Standard config. (ALWAYS DONE, but can be precomputed if no- or constant-key.)
        //<!--These below are not used in this implementation.  If you can figure them out from the white paper, feel free!
        // Skein is a very versitile algorithm, and I'd like to expand this to use all its features.
        // This implementation, however does NOT use the tree-hashing in the white paper.
        // If you need it, please put it in here!  
        // The more this gets flushed out, the more useful it becomes for all! :)
        //private const UInt64 SKEIN_TYPE_PER_STR = 0x0800000000000000;   // Personalization string. 
                                                                        // Use the Personalization string like a message block
                                                                        // after the config to narrow the scope of the particular
                                                                        // hash calculation.  This should be an input 
                                                                        // parameter to the functions.
        // private const UInt64 SKEIN_TYPE_PUB_KEY	= 0x0C00000000000000;   // For working with public keys.
        // private const UInt64 SKEIN_TYPE_KEY_ID  = 0x1000000000000000;   // Key identifier?? Not sure on this one.
        //private const UInt64 SKEIN_TYPE_NONCE   = 0x1400000000000000;   // Message nonce.  Not sure on this one either, but
                                                                        // I suspect this is for RNG (NOT PRNG) functionality,
                                                                        // or for stream ciphers.
        //-->
        private const UInt64 SKEIN_TYPE_MSG    = 0x3000000000000000;   // This block is message data.
        private const UInt64 SKEIN_TYPE_OUTPUT = 0x3F00000000000000;   // This block is part of the output transform.

        /// <summary>
        /// Enumerator for the sizes of the Skein state.
        /// </summary>
        public enum StateSize : ushort
        {   ///<summary>256 bits</summary>
            Narrow = 256,
            ///<summary>512 bits</summary>
            Medium = 512,
            ///<summary>1024 bits</summary>
            Wide = 1024
        }

        //This was intended to be used by System.Security.Cryptography.SkeinX modules.  Leave it for now.
        /*private struct SkeinState
        {
            UInt64[] key;       //key material for the ThreeFish transforms
            UInt64[] payload;   //this is basically the "INPUT" to the ThreeFish transforms
            UInt64[] tweak;     //this is only used during the OUTPUT transformation as it
                                // is the only portion of Skein that maintains a count
                                //if "tweak" not null, assume finalized at least once
        }*/

        //CLASS-WIDE COMMON METHODS/FUNCTIONS
        
        /// <summary>
        /// Zero out an array of 64-bit unsigned words.
        /// </summary>
        /// <param name="inWords">Array to be zeroed out.</param>
        private static void ClearWords(UInt64[] inWords)
        {
            for (int i = inWords.GetLowerBound(0); i <= inWords.GetUpperBound(0); i++)
            {
                inWords[i] = 0;   //this extra stuff is to prevent the compiler from optimizing these steps out
                inWords[i] |= 0xFFFFFFFFFFFFFFFF;
                inWords[i] &= 0;   // it's less likely in .NET than true C/C++, but this also helps to secure memory.
            }
        }
        
    }
}
